home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 019a / view002.zip / VIEW.C < prev    next >
C/C++ Source or Header  |  1991-09-14  |  25KB  |  1,051 lines

  1. /*
  2. View 0.02 - A simple,small,windowed, text file viewer.
  3.  
  4. Copyright (c) 1991 James P. Goodwin.
  5. All rights reserved.
  6.  
  7. Redistribution and use in source and binary forms are per-
  8. mitted provided that the above copyright notice is dupli-
  9. cated in all such forms and that any documentation,
  10. advertising materials, and other materials related to such
  11. distribution and use acknowledge that the software was
  12. developed by James P. Goodwin.
  13.  
  14. THE SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS
  15. OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE
  16. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PAR-
  17. TICULAR PURPOSE.
  18. */
  19.  
  20.  
  21. #include <stdio.h>
  22. #include <fcntl.h>
  23. #include <sys\types.h>
  24. #include <sys\stat.h>
  25. #include <io.h>
  26. #include <share.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <dos.h>
  30. #include <share.h>
  31. #include <conio.h>
  32. #include <limits.h>
  33. #include <direct.h>
  34. #include "view.h"
  35.  
  36. /*
  37.   GLOBAL variable initialization 
  38. */
  39. VIEW *viewstack = NULL;                  /* pointer to the bottom view on screen */
  40.  
  41. UCHAR _far *screen;              /* pointer to display ram */
  42.  
  43. #if VIEW_HAS_MEMORY
  44.                                          /* huge 0 pointer to memory */
  45. UCHAR _huge *memory = (char _huge *)0;
  46. #endif
  47.                                          /* characters used in hex/dec conversion routines */
  48. UCHAR  hexdigits[] = {"0123456789ABCDEF"};
  49.  
  50. int view_offset   = 0;                   /* current offset into display memory */
  51. int view_attr     = 0;                   /* current display attribute */
  52. int view_is_mono  = FALSE;               /* flag indicates mono (TRUE) or color (FALSE) */
  53. int view_cols     = 80;
  54. int view_rows     = 25;
  55. UCHAR _far *bios_rows = (UCHAR _far *)0x00400084;
  56. UINT _far *bios_cols  = (UINT _far *)0x0040004A;
  57.  
  58. UCHAR *view_line   = NULL;                /* line input buffer */
  59.  
  60. #if VIEW_HAS_DIR
  61.  
  62. UCHAR *view_curdir = NULL;                /* current directory when view entered */
  63. UINT   view_curdrive = 0;
  64.  
  65. #endif
  66.  
  67. /*
  68.   Array of attributes for color and monochrome displays
  69. */
  70.  
  71. int view_attr_list[2][5] = {
  72.                              {     /* Color Attributes */
  73.                              0x1f, /* Active Window */
  74.                              0x30, /* Inactive Window */
  75.                              0x4f, /* Error Message */
  76.                              0x1b, /* Get a String  */
  77.                              0x31  /* Get a String Cursor */
  78.                              }, 
  79.                              {     /* Mono Attributes */
  80.                              0x0f, /* Active Window */
  81.                              0x70, /* Inactive Window */
  82.                              0x0f, /* Error Message */
  83.                              0x01, /* Get a String  */
  84.                              0x70  /* Get a String Cursor */
  85.                              }
  86.                            };
  87.  
  88. /*
  89.  
  90.    Function: main( int argc, UCHAR *argv[] )
  91.  
  92.    Description: 
  93.      This function will :
  94.  
  95.      1) close any "extra" file handles we inherited from
  96.      whoever ran us to give us more views
  97.  
  98.      2) save the current directory
  99.  
  100.      3) figure out whether we're in color or monochrome and set the
  101.      video buffer address in screen
  102.  
  103.      4) check the standard input to see if it's a file and
  104.      if so add it to the list of views and open a new standard
  105.      input.
  106.  
  107.      5) if we have no command line arguments prompt for file name
  108.  
  109.      6) process all command line arguments as if they were file names
  110.  
  111.      7) go into the view user interface and view files
  112.  
  113.      8) if we exit this way restore current directory
  114. */
  115.  
  116. main( int argc, UCHAR *argv[] )
  117. {
  118.   int i;
  119.   char fname[15];
  120.  
  121.   _harderr(view_errfunc);
  122.                                          /* Close "extra" file handles */
  123.   _dos_close(fileno(stderr));
  124.   _dos_close(fileno(stdaux));
  125.   _dos_close(fileno(stdprn));
  126.   _dos_close(fileno(stdout));
  127.                                          /* Assume :) that video mode 7 is monochrome */
  128.   if (view_getvidmode() == 7)
  129.     {
  130.     view_is_mono = TRUE;
  131.     screen = (UCHAR _far *)0xB0000000;
  132.     }
  133.   else
  134.     {
  135.     view_is_mono = FALSE;
  136.     screen = (UCHAR _far *)0xB8000000;
  137.     }
  138.  
  139.   view_rows = (*bios_rows)+1;
  140.   view_cols = (*bios_cols);
  141.                                          /* Save the current directory */
  142. #if VIEW_HAS_DIR
  143.   _dos_getdrive(&view_curdrive);
  144.   view_curdir = getcwd(NULL,80);
  145.   if (!view_curdir)
  146.     view_error(1,"VIEW0001");
  147. #endif
  148.                                          /* If stdin is a file then add it */
  149.   if (!isatty(fileno(stdin))) 
  150.     view_new(NULL,0,0,16,45);
  151.                                          /* If no args prompt for file */
  152.   if (argc <= 1 && !viewstack )
  153.     {
  154. #if VIEW_HAS_NEWFILE
  155.     view_newfile();
  156. #else
  157.     view_error(1,"[command |]VIEW [<filename] [filename .. filenameN]");
  158. #endif
  159.     }
  160.   else                                   /* process args as file names */
  161.     {
  162.     for (i = 1; i < argc; i ++)
  163.       view_new(argv[i],0,0,16,45);
  164.     }
  165.                                          /* put it on the screen and play */
  166.                                          /* with it */
  167.   view();
  168.  
  169. #if VIEW_HAS_DIR
  170.   if (view_curdir)                       /* return to saved dir and release memory */
  171.     {
  172.     _dos_setdrive(view_curdrive,&i);
  173.     chdir(view_curdir);
  174.     free(view_curdir);
  175.     }
  176. #endif
  177. }
  178. /*
  179.    Function: void view(void)
  180.  
  181.    Description:
  182.      This function puts up the user interface for view and accepts the
  183.      users input. It is basically a big switch on what key they hit. The
  184.      keys break down into extended and regular, extended keys are always
  185.      preceded by a null scan code.
  186.  
  187.      There are a set of offsets row_offset,col_offset etc... these are
  188.      set when certain keys are hit and are added to their corresponding
  189.      fields. The view_refresh routine enforces all dimensional constraints
  190.      so we don't worry about "overflow" or "underflow" in this routine.
  191.  
  192.      If page_offset is set to a non-zero value then the file is read 
  193.      either forwards or backwards abs(page_offset) times.
  194.  
  195.      The different refresh modes are used to speed up the screen update
  196.      when only the top window needs to be updated or only the top window's
  197.      contents.
  198. */
  199. void view(void)
  200. {
  201.   int c1;                                /* first character read */
  202.   int c2;                                /* second character read */
  203.   int row_offset;                        /* change row of window */
  204.   int col_offset;                        /* change col of window */
  205.   int height_offset;                     /* change height of window */
  206.   int width_offset;                      /* change width of window */
  207.   int line_offset;                       /* change coff of window */
  208.   int page_offset;                       /* change page of contents of window */
  209.   int refresh_mode;                      /* see refresh modes in view.h */
  210.   VIEW *top;                             /* temporary ptr to top window */
  211.  
  212.   if (!viewstack) return;                /* there aren't any views so return */
  213.  
  214.   if (!view_line)                        /* allocate the line buffer if NULL */
  215.     {
  216.     if (!(view_line = malloc(VIEW_MAX_LINE+1)))
  217.       view_error(1,"VIEW0002");
  218.     }
  219.  
  220.   view_tile();                           /* arrange the windows nicely */
  221.   top = viewstack;
  222.   do
  223.     {
  224.     view_scroll(top,SCROLL_RESET);
  225.     top = top->next;
  226.     }
  227.   while( top != viewstack );
  228.  
  229.   view_refresh(REFRESH_ALL);             /* put them on the screen */
  230.  
  231.  
  232.   for(;;)
  233.     {
  234.     refresh_mode = REFRESH_ALL;          /* reset change variables */
  235.     row_offset   = 0;
  236.     col_offset   = 0;
  237.     height_offset= 0;
  238.     width_offset = 0;
  239.     line_offset  = 0;
  240.     page_offset  = SCROLL_NONE;
  241.  
  242.     c1 = getch();                        /* get a keystroke from console */
  243.     
  244.     switch( c1 )                         /* select an action based on key */
  245.       {
  246.       case 0:                            /* an extended key follows */
  247.         c2 = getch();                    /* get extended keysroke */
  248.  
  249.         switch(c2)
  250.           {
  251.           case CURSOR_DOWN:
  252.             refresh_mode = REFRESH_CONTENTS;
  253.             page_offset = SCROLL_DOWN;
  254.           break;
  255.  
  256.           case CURSOR_LEFT:
  257.             refresh_mode = REFRESH_CONTENTS;
  258.             line_offset = -3;
  259.           break;
  260.  
  261.           case CURSOR_RIGHT:
  262.             refresh_mode = REFRESH_CONTENTS;
  263.             line_offset = 3;
  264.           break;
  265.  
  266.           case CURSOR_UP:
  267.             refresh_mode = REFRESH_CONTENTS;
  268.             page_offset = SCROLL_UP;
  269.           break;
  270.  
  271.           case CNTL_CURSOR_LEFT:
  272.             refresh_mode = REFRESH_TOP;
  273.             col_offset = -3;
  274.           break;
  275.  
  276.           case CNTL_CURSOR_RIGHT:
  277.             refresh_mode = REFRESH_TOP;
  278.             col_offset = 3;
  279.           break;
  280.  
  281.           case CNTL_PGUP:
  282.             refresh_mode = REFRESH_TOP;
  283.             row_offset = -1;
  284.           break;
  285.  
  286.           case CNTL_PGDN:
  287.             refresh_mode = REFRESH_TOP;
  288.             row_offset = 1;
  289.           break;
  290.  
  291.           case CNTL_HOME:
  292.             view_tile();
  293.             height_offset = view_rows;
  294.             width_offset = view_cols;
  295.           break;
  296.  
  297.           case CNTL_END:
  298.             view_tile();
  299.           break;
  300.  
  301.           case PGDN:
  302.             refresh_mode = REFRESH_CONTENTS;
  303.             page_offset = SCROLL_PAGE_DOWN;
  304.           break;
  305.  
  306.           case PGUP:
  307.             refresh_mode = REFRESH_CONTENTS;
  308.             page_offset = SCROLL_PAGE_UP;
  309.           break;
  310.  
  311.           case HOME:
  312.             refresh_mode = REFRESH_CONTENTS;
  313.             page_offset  = SCROLL_HOME;
  314.           break;
  315.  
  316.           case END:
  317.             refresh_mode = REFRESH_CONTENTS;
  318.             page_offset  = SCROLL_END;
  319.           break;
  320.  
  321.           case SHIFT_TAB:
  322.             view_refresh(REFRESH_PREV);
  323.             page_offset  = SCROLL_RESET;
  324.           break;
  325.  
  326.           default:
  327.           continue;
  328.           }
  329.       break;
  330.  
  331.       case 'e':
  332.       case 'E':
  333.          view_refresh(REFRESH_OFF);
  334.  
  335.          if (view_rows < 43)
  336.            {
  337.            _asm
  338.               {
  339.               push es
  340.               mov  ax,40H
  341.               mov  es,ax
  342.               push es:[87H]
  343.               or   byte ptr es:[87H],1
  344.  
  345.               mov  ax,1112H
  346.               xor  bx,bx
  347.               int  10h
  348.  
  349.               pop  es:[87H]
  350.               pop  es
  351.  
  352.               mov  ax,1200H
  353.               mov  bx,0020H
  354.               int  10h
  355.               }
  356.             }
  357.           else
  358.             {
  359.             _asm
  360.                {
  361.                push es
  362.                mov  ax,40H
  363.                mov  es,ax
  364.                push es:[87H]
  365.                or   byte ptr es:[87H],1
  366.  
  367.                mov ax,1111H
  368.                xor bx,bx
  369.                int 10h
  370.  
  371.                pop  es:[87H]
  372.                pop  es
  373.                }
  374.             }
  375.  
  376.          view_rows = (*bios_rows)+1;
  377.          view_cols = (*bios_cols);
  378.          view_tile();
  379.          refresh_mode = REFRESH_ALL;
  380.       break;
  381.  
  382.  
  383.       case 'w':
  384.         refresh_mode = REFRESH_TOP;
  385.         width_offset = -3;
  386.       break;
  387.  
  388.       case 'W':
  389.         refresh_mode = REFRESH_TOP;
  390.         width_offset = 3;
  391.       break;
  392.  
  393.       case 'h':
  394.         refresh_mode = REFRESH_TOP;
  395.         height_offset = -3;
  396.       break;
  397.  
  398.       case 'H':
  399.         refresh_mode = REFRESH_TOP;
  400.         height_offset = 3;
  401.       break;
  402.  
  403.       case 'C':
  404.       case 'c':
  405.         view_new(viewstack->prev->vf->fname,viewstack->prev->row,viewstack->prev->col,viewstack->prev->rows,viewstack->prev->cols);
  406.         view_tile();
  407.         page_offset  = SCROLL_RESET;
  408.       break;
  409.  
  410. #if VIEW_HAS_GOTO
  411.       case 'g':
  412.       case 'G':
  413.         refresh_mode = REFRESH_CONTENTS;
  414.         page_offset  = SCROLL_RESET;
  415.         view_goto_line();
  416.       break;
  417. #endif
  418.  
  419. #if VIEW_HAS_SEARCH
  420.       case 'S':
  421.       case 's':
  422.         refresh_mode = REFRESH_CONTENTS;
  423.         page_offset  = SCROLL_RESET;
  424.         view_search();
  425.       break;
  426. #endif
  427.  
  428.  
  429. #if VIEW_HAS_NEWFILE
  430.       case 'F':
  431.       case 'f':
  432.         if (!view_newfile()) continue;
  433.         view_tile();
  434.         page_offset = SCROLL_RESET;
  435.       break;
  436. #endif
  437.  
  438.       case 'D':
  439.       case 'd':
  440.         view_delete();
  441.         view_tile();
  442.       break;
  443.  
  444. #if VIEW_HAS_RAW
  445.       case 'X':
  446.       case 'x':
  447.         viewstack->prev->vf->lmode = VIEW_HEX_MODE;
  448.         page_offset = SCROLL_RESET;
  449.       break;
  450.  
  451.       case 'B':
  452.       case 'b':
  453.         viewstack->prev->vf->lmode = VIEW_BIN_MODE;
  454.         page_offset = SCROLL_RESET;
  455.       break;
  456. #endif
  457.  
  458.       case TAB:
  459.         view_refresh(REFRESH_NEXT);
  460.         page_offset  = SCROLL_RESET;
  461.       break;
  462.  
  463.       case ESC:
  464.         view_quit();
  465.       break;
  466.  
  467.       default:
  468.       continue;
  469.       }
  470.  
  471.     top       = viewstack->prev;
  472.     top->row  += row_offset;
  473.     top->col  += col_offset;
  474.     top->coff += line_offset;
  475.     top->rows += height_offset;
  476.     top->cols += width_offset;
  477.  
  478.     view_scroll(top,page_offset);
  479.     view_refresh(refresh_mode);
  480.     }
  481.  
  482. void view_scroll( VIEW *current, int mode )
  483. {
  484.    int      i;
  485.    VIEWFILE *vf;
  486.    ULONG    *pos;
  487.    UCHAR    **lines;
  488.  
  489.    if (kbhit())
  490.      if (!getch()) getch();
  491.  
  492.    vf    = current->vf;
  493.    pos   = current->pos;
  494.    lines = current->lines;
  495.  
  496.    switch( mode )
  497.      {
  498.      case SCROLL_NONE     :
  499.      return;
  500.  
  501.      case SCROLL_DOWN     :
  502.        if (lines[0])
  503.          {
  504.          view_seek(vf,pos[(VIEW_LINE_VIEW-1)],SEEK_SET);
  505.          view_getl_fwd(vf,view_line,VIEW_MAX_LINE);
  506.  
  507.          memmove(pos,pos+1,(VIEW_LINE_VIEW-1)*sizeof(ULONG));
  508.  
  509.          if (lines[0]) free(lines[0]);
  510.  
  511.          memmove(lines,lines+1,(VIEW_LINE_VIEW-1)*sizeof(UCHAR *));
  512.  
  513.          pos[(VIEW_LINE_VIEW-1)] = view_tell(vf);
  514.  
  515.          if (!view_getl_fwd(vf,view_line,VIEW_MAX_LINE))
  516.            lines[(VIEW_LINE_VIEW-1)] = view_strdup(view_line);
  517.          else
  518.            {
  519.            lines[(VIEW_LINE_VIEW-1)] = NULL;
  520.            pos[(VIEW_LINE_VIEW-1)]   = LONG_MAX;
  521.            }
  522.          }
  523.      break;
  524.  
  525.  
  526.      case SCROLL_UP       :
  527.        if (pos[0])
  528.          {
  529.          view_seek(vf,pos[0],SEEK_SET);
  530.  
  531.          memmove(pos+1,pos,(VIEW_LINE_VIEW-1)*sizeof(ULONG));
  532.  
  533.          if (lines[(VIEW_LINE_VIEW-1)]) free(lines[(VIEW_LINE_VIEW-1)]);
  534.                     
  535.          memmove(lines+1,lines,(VIEW_LINE_VIEW-1)*sizeof(UCHAR *));
  536.  
  537.          view_getl_bwd(vf,view_line,VIEW_MAX_LINE);
  538.  
  539.          pos[0] = view_tell(vf);
  540.  
  541.          view_getl_fwd(vf,view_line,VIEW_MAX_LINE);
  542.  
  543.          lines[0] = view_strdup(view_line);
  544.          }
  545.      break;
  546.  
  547.      case SCROLL_PAGE_UP  :
  548.        for (i = 0; i < (current->rows-2); i++)
  549.          view_scroll(current,SCROLL_UP);
  550.      break;
  551.  
  552.      case SCROLL_PAGE_DOWN:
  553.        for (i = 0; i < (current->rows-2); i++)
  554.          view_scroll(current,SCROLL_DOWN);
  555.      break;
  556.  
  557.      case SCROLL_HOME     :
  558.        view_seek(vf,0L,SEEK_SET);
  559.        view_scroll(current,SCROLL_RESET);
  560.      break;
  561.  
  562.      case SCROLL_END      :
  563.        view_seek(vf,0L,SEEK_END);
  564.        view_scroll(current,SCROLL_RESET);
  565.        view_scroll(current,SCROLL_PAGE_UP);
  566.      break;
  567.  
  568.      case SCROLL_CLEAR    :
  569.        for (i = 0; i < VIEW_LINE_VIEW; i ++)
  570.          {
  571.          pos[i] = LONG_MAX;
  572.          if (lines[i])
  573.            {
  574.            free(lines[i]);
  575.            lines[i] = NULL;
  576.            }
  577.          }
  578.  
  579.        return;
  580.      break;
  581.  
  582.      case SCROLL_RESET    :
  583.  
  584.        view_scroll(current,SCROLL_CLEAR);
  585.  
  586.        for (i = 0; i < VIEW_LINE_VIEW; i ++ )
  587.          {
  588.          pos[i] = view_tell(vf);
  589.          if (!view_getl_fwd(vf,view_line,VIEW_MAX_LINE))
  590.            lines[i] = view_strdup(view_line);
  591.          else
  592.            break;
  593.          }
  594.      break;
  595.      }
  596.  
  597.   view_seek(vf,pos[0],SEEK_SET);
  598. }
  599.  
  600.  
  601. void view_new( UCHAR *fname, int row,int col,int rows,int cols )
  602. {
  603.   VIEW *new;
  604.   int th;
  605.  
  606.   if (!strcmp(fname,"Standard Input")) return;
  607.  
  608.   new = (VIEW *)malloc(sizeof(VIEW));
  609.   if (!new) view_error(1,"VIEW0003");
  610.  
  611.   if (!(new->vf = view_open(fname)))
  612.     {
  613.     free(new);
  614.     return;
  615.     }
  616.  
  617.   new->row  = row;
  618.   new->col  = col;
  619.   new->rows = rows;
  620.   new->cols = cols;
  621.   memset(new->pos,'\0',VIEW_LINE_VIEW*sizeof(ULONG));
  622.   memset(new->lines,'\0',VIEW_LINE_VIEW*sizeof(UCHAR *));
  623.   new->coff = 0;
  624.   new->save = NULL;
  625.  
  626.  
  627.   if (viewstack == NULL)
  628.     {
  629.     new->next = new;
  630.     new->prev = new;
  631.     viewstack = new;
  632.     }
  633.   else
  634.     {
  635.     new->next = viewstack;
  636.     new->prev = viewstack->prev;
  637.     viewstack->prev->next = new;
  638.     viewstack->prev = new;
  639.     }
  640. }
  641.  
  642. void view_restore( VIEW *trav )
  643. {
  644.    view_putsave(trav->save);
  645.    trav->save = NULL;
  646. }
  647.  
  648. void view_save( VIEW *trav )
  649. {
  650.    trav->save = view_getsave(trav->row,trav->col,trav->rows,trav->cols);
  651. }
  652.  
  653. void view_refresh(int refresh_mode)
  654. {
  655.    VIEW *trav;
  656.    int  r;
  657.    int  blank;
  658.    UCHAR _far *oscreen;
  659.  
  660.    if (refresh_mode != REFRESH_CONTENTS && refresh_mode != REFRESH_TOP)
  661.      {
  662.      oscreen = screen;
  663.  
  664.      screen = malloc(view_rows*(view_cols*2));
  665.      if (!screen)
  666.        {
  667.        screen = oscreen;
  668.        }
  669.      else
  670.        {
  671.        memmove(screen,oscreen,view_rows*(view_cols*2));
  672.        }
  673.      }
  674.  
  675.    if (refresh_mode != REFRESH_CONTENTS)
  676.      {
  677.      trav = viewstack->prev;
  678.  
  679.      do
  680.        {
  681.        if (trav->save)
  682.          view_restore(trav);
  683.      
  684.        trav = trav->prev;
  685.  
  686.        if (refresh_mode == REFRESH_CONTENTS || refresh_mode == REFRESH_TOP) break;
  687.        }
  688.      while(trav != viewstack->prev);
  689.      }
  690.  
  691.    if (refresh_mode == REFRESH_NEXT)
  692.      {
  693.      viewstack = viewstack->next;
  694.      refresh_mode = REFRESH_ALL;
  695.      }
  696.  
  697.    if (refresh_mode == REFRESH_PREV)
  698.      {
  699.      viewstack = viewstack->prev;
  700.      refresh_mode = REFRESH_ALL;
  701.      }
  702.  
  703.    if (refresh_mode != REFRESH_OFF) 
  704.      {
  705.      if (refresh_mode != REFRESH_ALL)
  706.        trav = viewstack->prev;
  707.      else
  708.        trav = viewstack;
  709.  
  710.      do 
  711.        {
  712.        if (trav == viewstack->prev)
  713.          view_attr = ACTIVE_WINDOW;
  714.        else
  715.          view_attr = INACTIVE_WINDOW;
  716.  
  717.        trav->rows = max(trav->rows,3);
  718.        trav->rows = min(trav->rows,view_rows);
  719.        trav->cols = max(trav->cols,3);
  720.        trav->cols = min(trav->cols,view_cols);
  721.  
  722.        trav->col  = max(trav->col,0);
  723.        trav->col  = min(trav->col,view_cols-trav->cols);
  724.  
  725.        trav->row  = max(trav->row,0);
  726.        trav->row  = min(trav->row,view_rows-trav->rows);
  727.                                
  728.        trav->coff = max(trav->coff,0);
  729.  
  730.        if (refresh_mode != REFRESH_CONTENTS)
  731.          {
  732.          view_save(trav);
  733.          view_frame(trav->vf->fname,trav->row,trav->col,trav->rows,trav->cols);
  734.          }
  735.  
  736.        for (r = 1; r < trav->rows-1; r ++)
  737.          {
  738.          blank = TRUE;
  739.          view_goto(trav->row+r,trav->col+1);
  740.  
  741.          if (trav->lines[r-1] && (strlen(trav->lines[r-1]) > trav->coff))
  742.            {
  743.            view_puts(trav->lines[r-1]+trav->coff,trav->cols-2);
  744.            blank = FALSE;
  745.            }
  746.  
  747.          if (blank) view_fill(' ',trav->cols-2);
  748.          }
  749.  
  750.        trav = trav->next;
  751.  
  752.        if (refresh_mode != REFRESH_ALL) break;
  753.        } 
  754.      while(trav != viewstack);
  755.      }
  756.  
  757.    if (refresh_mode == REFRESH_ALL || refresh_mode == REFRESH_OFF)
  758.      {
  759.      if (screen != oscreen)
  760.        {
  761.        memmove(oscreen,screen,view_rows*(view_cols*2));
  762.        free(screen);
  763.        screen = oscreen;
  764.        }
  765.      }
  766. }
  767.  
  768. void view_quit( void )
  769. {
  770.   for(;;) view_delete();
  771. }
  772.  
  773. void view_tile( void )
  774. {
  775. #if VIEW_HAS_TILE
  776.  
  777.   VIEW *trav;
  778.   int windows;
  779.   int vsize,hsize;
  780.   int row,col;
  781.  
  782.   if (!viewstack) return;
  783.  
  784.   windows = 0;
  785.   trav    = viewstack;
  786.  
  787.   do
  788.     {
  789.     windows ++;
  790.     trav = trav->next;
  791.     }
  792.   while (trav != viewstack);
  793.  
  794.   hsize = view_cols;
  795.   vsize = view_rows;
  796.  
  797.   while ( (view_cols/hsize)*(view_rows/vsize) < windows )
  798.     vsize --;
  799.  
  800.   if (vsize < 3)
  801.     {
  802.     vsize = view_rows;
  803.     while ( (view_cols/hsize)*(view_rows/vsize) < windows )
  804.       hsize --;
  805.     }
  806.  
  807.   if (hsize < 10)
  808.     {
  809.     hsize = view_cols;
  810.     vsize = 24;
  811.  
  812.     while ( (view_cols/hsize)*(view_rows/vsize) < windows )
  813.       {
  814.       hsize -= 3;
  815.       vsize --;
  816.       }
  817.     }
  818.     
  819.   trav = viewstack;
  820.   row  = 0;
  821.   col  = 0;
  822.  
  823.   do
  824.     {
  825.     trav->row = row;
  826.     trav->col = col;
  827.     trav->rows = vsize;
  828.     trav->cols = hsize;
  829.  
  830.     col += hsize;
  831.     if (col+hsize > view_cols)
  832.       {
  833.       col = 0;
  834.       row += vsize;
  835.       }
  836.     trav = trav->next;
  837.     }
  838.   while(trav != viewstack);
  839.  
  840. #endif /* VIEW_HAS_TILE */
  841. }
  842.   
  843. void view_delete( void )
  844. {
  845.    VIEW *hold;
  846.    int lets_exit = FALSE;
  847.    
  848.  
  849.    if (viewstack->prev == viewstack)
  850.      lets_exit = TRUE;
  851.  
  852.    hold = viewstack->prev;
  853.    viewstack->prev->prev->next = viewstack;
  854.    viewstack->prev = viewstack->prev->prev;
  855.    view_restore(hold);
  856.    view_scroll(hold,SCROLL_CLEAR);
  857.    view_close(hold->vf);
  858.    free(hold);
  859.  
  860.    if (lets_exit) 
  861.      {
  862.      if (view_line) free(view_line);
  863.  
  864. #if VIEW_HAS_DIR
  865.      if (view_curdir)
  866.        {
  867.        _dos_setdrive(view_curdrive,&lets_exit);
  868.        chdir(view_curdir);
  869.        free(view_curdir);
  870.        }
  871. #endif
  872.      exit(0);
  873.      }
  874. }
  875.  
  876. #if VIEW_HAS_NEWFILE
  877. int view_newfile( void )
  878. {
  879.   int c1,c2;
  880.   char fname[80];
  881.  
  882.   fname[0] = '\0';
  883.  
  884.   do
  885.     {
  886.     c1 = view_prompt("New File","Filename:",fname,40);
  887.  
  888. #if VIEW_HAS_DIR
  889.     if (c1 && !strlen(fname))
  890.       c1 = view_dir(fname);
  891. #endif
  892.  
  893.     if (c1 && (c2 = (access(fname,0)
  894. #if VIEW_HAS_MEMORY
  895.     && stricmp(fname,VIEW_MEM_NAME)
  896. #endif
  897.     ))) 
  898.       {
  899.       strcpy(fname,"File Not Found");
  900.       }
  901.     }
  902.   while(c1 && c2);
  903.  
  904.   if (c1)
  905.     {
  906.     view_new(fname,0,0,16,45);
  907.     return(TRUE);
  908.     }
  909.   else
  910.     return(FALSE);
  911. }
  912. #endif /* VIEW_HAS_NEWFILE */
  913.  
  914. #if VIEW_HAS_SEARCH
  915. int view_search( void )
  916. {
  917.   int c1,c2;
  918.   char pat[80];
  919.   UCHAR *found;
  920.   ULONG pos;
  921.   int ret;
  922.   VIEWFILE *vf;
  923.  
  924.   vf = viewstack->prev->vf;
  925.  
  926.  
  927.   pat[0] = '\0';
  928.  
  929.   do
  930.     {
  931.     c1 = view_prompt("Search","Pattern:",pat,40);
  932.  
  933.     if (c1)
  934.       {
  935.       view_seek(vf,viewstack->prev->pos[0],SEEK_SET);
  936.  
  937.       ret   = 0;
  938.       found = NULL;
  939.  
  940.       while(!ret && !found)
  941.         {
  942.         pos = view_tell(vf);
  943.         ret = view_getl_fwd(vf,view_line,VIEW_MAX_LINE);
  944.         if (!ret) found = strstr(view_line,pat);
  945.         }
  946.  
  947.       if (found)
  948.         {
  949.         view_seek(vf,pos,SEEK_SET);
  950.         viewstack->prev->coff = found-view_line;
  951.         return(TRUE);
  952.         }
  953.       else
  954.         strcpy(pat,"Pattern Not Found");
  955.       }
  956.     }
  957.   while(c1);
  958.  
  959.   return(FALSE);
  960. }
  961. #endif
  962.  
  963.  
  964. #if VIEW_HAS_GOTO
  965. void view_goto_line( void )
  966. {
  967.   int c1;
  968.   char pat[80];
  969.   ULONG pos;
  970.   int ret;
  971.   VIEWFILE *vf;
  972.   UCHAR *goto_pmt[] = {"Offset In File:","Memory Address (SSSSOOOO):","Line Number:"};
  973.   int   goto_len[]  = { 10, 8, 8 };
  974.   int   goto_base[] = { 10,16,10 };
  975.   int   goto_type;
  976.  
  977.   pat[0] = '\0';
  978.   vf = viewstack->prev->vf;
  979.  
  980.  
  981. #if VIEW_HAS_RAW
  982.   if (vf->lmode 
  983.  
  984. #if VIEW_HAS_MEMORY
  985.   && vf->fh != VIEW_MEM_HDL
  986. #endif
  987.  
  988.   )
  989.     goto_type = 0;
  990.  
  991. #if VIEW_HAS_MEMORY
  992.   else if (vf->lmode  && vf->fh == VIEW_MEM_HDL )
  993.     goto_type = 1;
  994. #endif
  995.  
  996.   else
  997. #endif /* VIEW_HAS_RAW */
  998.     goto_type = 2;
  999.  
  1000.   c1 = view_prompt("Goto",goto_pmt[goto_type],pat,goto_len[goto_type]);
  1001.  
  1002.   if (c1)  
  1003.     {  
  1004.     pos = view_atoul(pat,goto_base[goto_type]);  
  1005.  
  1006.  
  1007.     switch(goto_type)  
  1008.       {  
  1009. #if VIEW_HAS_RAW
  1010.       case 0:  
  1011.         view_seek(vf,pos,SEEK_SET);  
  1012.       break;  
  1013. #endif
  1014.  
  1015. #if VIEW_HAS_MEMORY
  1016.       case 1:  
  1017.         view_seek(vf,(ULONG)(((UCHAR _huge *)pos)-memory),SEEK_SET);  
  1018.       break;  
  1019. #endif
  1020.  
  1021.       case 2:  
  1022.         view_seek(vf,0L,SEEK_SET);  
  1023.  
  1024.         ret = 0;
  1025.         while (!ret && pos)  
  1026.           {  
  1027.           ret = view_getl_fwd(vf,view_line,VIEW_MAX_LINE);  
  1028.           pos --;  
  1029.           }  
  1030.       break;  
  1031.       }  
  1032.     }  
  1033. }
  1034. #endif /* VIEW_HAS_GOTO */
  1035.  
  1036. void _far view_errfunc( void )
  1037.   _hardresume(_HARDERR_FAIL);
  1038. }
  1039.  
  1040. UCHAR *view_strdup( UCHAR *str )
  1041. {
  1042.    str = strdup(str);
  1043.  
  1044.    if (!str)
  1045.      view_error(1,"VIEW0010");
  1046.  
  1047.    return(str);
  1048. }
  1049.